package com.lanmao.emc.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.ReindexRequest;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 描述：
 *
 * @author lanmao
 * @since 2024年11月11日 20:43
 */

@Slf4j
public class EsUtils {
    private static final RestHighLevelClient CLIENT = SpringContextUtils.getBean(RestHighLevelClient.class);

    public static boolean existsIndex(String index) throws IOException {
        GetIndexRequest request = new GetIndexRequest(index);
        return CLIENT.indices().exists(request, RequestOptions.DEFAULT);
    }

    public static List<String> getIndexAlias(String index) throws IOException {
        GetIndexRequest request = new GetIndexRequest(index);
        GetIndexResponse response = CLIENT.indices().get(request, RequestOptions.DEFAULT);
        return response.getAliases().values().stream().flatMap(Collection::stream).map(AliasMetadata::alias).toList();
    }

    public static void createAlias(String index, String... aliases) throws IOException {
        IndicesAliasesRequest request = new IndicesAliasesRequest();
        for (String alias : aliases) {
            IndicesAliasesRequest.AliasActions aliasActions = new IndicesAliasesRequest
                    .AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD).index(index).alias(alias);
            request.addAliasAction(aliasActions);
        }
        CLIENT.indices().updateAliases(request, RequestOptions.DEFAULT);
    }

    public static void delIndex(String index) throws IOException {
        DeleteIndexRequest indexRequest = new DeleteIndexRequest(index);
        CLIENT.indices().delete(indexRequest, RequestOptions.DEFAULT);
    }


    public static void addIndex(String index, String json) throws IOException {
        CreateIndexRequest request = new CreateIndexRequest(index);
        request.source(json, XContentType.JSON);
        request.setTimeout(TimeValue.timeValueSeconds(10));
        CLIENT.indices().create(request, RequestOptions.DEFAULT);
    }

    public static void updateByQuery(UpdateByQueryRequest request) throws IOException {
        CLIENT.updateByQuery(request, RequestOptions.DEFAULT);
    }

    public static long reindexAndGetCount(String srcIndex, String dstIndex) throws IOException {
        ReindexRequest request = new ReindexRequest();
        request.setSourceIndices(srcIndex);
        request.setDestIndex(dstIndex);
        request.setTimeout(TimeValue.timeValueMinutes(5));
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        builder.setRequestConfig(RequestConfig.custom().setSocketTimeout(300000).build());
        BulkByScrollResponse response = CLIENT.reindex(request, builder.build());
        return response != null ? response.getStatus().getCreated() : 0L;
    }

    public static void moveAliasToNewIndex(String oldIndex, String newIndex, String... aliases) throws IOException {
        IndicesAliasesRequest request = new IndicesAliasesRequest();
        for (String alias : aliases) {
            IndicesAliasesRequest.AliasActions removeAction = new IndicesAliasesRequest
                    .AliasActions(IndicesAliasesRequest.AliasActions.Type.REMOVE).index(oldIndex).alias(alias);
            IndicesAliasesRequest.AliasActions addAction = new IndicesAliasesRequest
                    .AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD).index(newIndex).alias(alias);
            request.addAliasAction(removeAction);
            request.addAliasAction(addAction);
        }
        CLIENT.indices().updateAliases(request, RequestOptions.DEFAULT);
    }

    public static void removeAlias(String indexName, String... aliases) throws IOException {
        IndicesAliasesRequest request = new IndicesAliasesRequest();
        for (String alias : aliases) {
            IndicesAliasesRequest.AliasActions removeAction = new IndicesAliasesRequest
                    .AliasActions(IndicesAliasesRequest.AliasActions.Type.REMOVE).index(indexName).alias(alias);
            request.addAliasAction(removeAction);
        }
        CLIENT.indices().updateAliases(request, RequestOptions.DEFAULT);
    }

    public static SearchResponse search(SearchSourceBuilder sourceBuilder, String... index) {
        SearchRequest searchRequest = new SearchRequest(index);
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = null;
        try {
            searchResponse = CLIENT.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("query es error ,", e);
        }
        return searchResponse;
    }

    public static void deleteByQuery(SearchSourceBuilder sourceBuilder, String index) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        SearchResponse search = search(sourceBuilder, index);
        for (SearchHit hit : search.getHits().getHits()) {
            DeleteRequest deleteIndexRequest = new DeleteRequest(index, hit.getId());
            bulkRequest.add(deleteIndexRequest);
        }
        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        CLIENT.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    public static <T> void bulk(List<T> data, String index) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        for (T t : data) {
            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(t));
            IndexRequest indexRequest = new IndexRequest(index);
            if (StringUtils.hasText(jsonObject.getString("id"))) {
                indexRequest.id(jsonObject.getString("id"));
            }
            indexRequest.source(jsonObject);
            bulkRequest.add(indexRequest);
        }
        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        CLIENT.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    public static <T> void save(T data, String index) throws IOException {
        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(data));
        IndexRequest indexRequest = new IndexRequest(index);
        if (StringUtils.hasText(jsonObject.getString("id"))) {
            indexRequest.id(jsonObject.getString("id"));
        }
        indexRequest.source(jsonObject);

        CLIENT.index(indexRequest, RequestOptions.DEFAULT);
    }

    public static <T> List<T> hitsToList(SearchHit[] hits, Class<T> tClass) {
        List<T> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            list.add(JSON.parseObject(hit.getSourceAsString(), tClass));
        }
        return list;
    }
}
